package com.kld.common.cardcore;

import com.kld.common.util.EncoderHandler;
import com.kld.common.util.PropertiesUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Properties;

/**
 * Created by Administrator on 2015/9/22.
 */

public class HsmUtil {

    /**
     * Logger for this class.
     */
    private static final Logger logger = LoggerFactory.getLogger(HsmUtil.class);

    private int BLOCK_SIZE = 1024;
    private int MAX_DATA_SIZE = 4096;

    public int HSM_TYPE;
    public String HSM_1_IP;
    public int HSM_1_PORT;
    public String HSM_2_IP;
    public int HSM_2_PORT;
    public String MAC_KEY;
    public String ENC_KEY;
    public int HSM_HEARD_LEN;

    public String C_HSM_IP;
    public int C_HSM_PORT;

    private int HSM_flag = 0;
    private int Long_conect = 0;

    private SocketUtil socketUtil = new SocketUtil();

    private String Heard = "111111111111111111111111111111111111111111111111";

    // 需要注入
    private static Properties propertiesHSM = new Properties();

    private String isDebugMode = PropertiesUtil.props.getProperty("hsmDebugMode").toString();

    static {
        try {
            logger.info("loading hsm configuration...");
            propertiesHSM.load(new InputStreamReader(HsmUtil.class.getResourceAsStream("/config/hsm.properties"), "UTF-8"));
            logger.info("hsm configuration loaded...");
        } catch (FileNotFoundException e) {
            logger.error("load properties error ", e);
        } catch (IOException e) {
            logger.error("load properties error ", e);
        }
    }

    public String getHSM(String key) {
        return propertiesHSM.getProperty(key);
    }

    /**
     * 初始化加密机
     *
     * @return 2：加密机2可用
     * 1：加密机1可用
     * 0：两台加密机均可用
     * -1：读取配置文件错误
     * -2：加密机配置错误； 应为1或2
     * -3：连接加密机失败
     * -4：加密机测试失败
     * @throws Exception
     */
    public int HSM_INI() {
        int HSM_COM_FLAG = -1;
        String Outstr = null, Instr = null;
        int ret = 0;
        HSM_flag = 0;
        try {
            HSM_TYPE = Integer.parseInt(getHSM("hsm_type"));
            HSM_1_IP = getHSM("hsm_1_ip");
            HSM_1_PORT = Integer.parseInt(getHSM("hsm_1_port"));
            HSM_2_IP = getHSM("hsm_2_ip");
            HSM_2_PORT = Integer.parseInt(getHSM("hsm_2_port"));
            MAC_KEY = getHSM("mac_key");
            ENC_KEY = getHSM("enc_key");
            HSM_HEARD_LEN = Integer.parseInt(getHSM("hsm_heard_len"));
            Long_conect = Integer.parseInt(getHSM("link_flag"));
        } catch (Exception e) {
            e.printStackTrace();
            return -1;
        }
        //hsm_type 为1代表产生MAC,2为验证MAC
        if (HSM_TYPE != 1 && HSM_TYPE != 2) {
            return -2;
        }
        Instr = Heard.substring(0, HSM_HEARD_LEN);
        //加密机1连接失败
        if (!socketUtil.connectHSM(HSM_1_IP, HSM_1_PORT)) {
            HSM_COM_FLAG = 0;
        } else {
            HSM_COM_FLAG = 1;
            try {
                if (HSM_TYPE == 1) {
                    Instr += "NC";
                    if ((Outstr = socketUtil.HSMCmd(Instr.length(), Instr)) == null) {
                        ret = 0;
                    } else if (Outstr.length() < HSM_HEARD_LEN + 4) {
                        ret = 0;
                    } else if (Outstr.substring(HSM_HEARD_LEN, HSM_HEARD_LEN + 4).equals("ND00")) {
                        ret = 1;
                    }
                } else {
                    Instr += "NC";
                    if ((Outstr = socketUtil.HSMCmd(Instr.length(), Instr)) == null) {
                        ret = 0;
                    } else if (Outstr.length() < HSM_HEARD_LEN + 4) {
                        ret = 0;
                    } else if (Outstr.substring(HSM_HEARD_LEN, HSM_HEARD_LEN + 4).equals("ND00")) {
                        ret = 1;
                    }
                }
            } catch (Exception e) {
                ret = 0;
            }
            //关闭加密机连接
            socketUtil.allClose();
            if (ret == 1) {
                HSM_flag = 1;
                C_HSM_IP = HSM_1_IP;
                C_HSM_PORT = HSM_1_PORT;
            } else {
                HSM_flag = 0;
            }
        }

        Instr = Heard.substring(0, HSM_HEARD_LEN);
        if (!socketUtil.connectHSM(HSM_2_IP, HSM_2_PORT)) {
            if (HSM_COM_FLAG == 0) {
                return -3;
            } else if (HSM_flag == 1) {
                return 1;
            }
        } else {
            try {
                if (HSM_TYPE == 1) {
                    Instr += "NC";
                    if ((Outstr = socketUtil.HSMCmd(Instr.length(), Instr)) == null) {
                        ret = 0;
                    } else if (Outstr.length() < HSM_HEARD_LEN + 4) {
                        ret = 0;
                    } else if (Outstr.substring(HSM_HEARD_LEN, HSM_HEARD_LEN + 4).equals("ND00")) {
                        ret = 1;
                    }
                } else {
                    Instr += "NC";
                    if ((Outstr = socketUtil.HSMCmd(Instr.length(), Instr)) == null) {
                        ret = 0;
                    } else if (Outstr.length() < HSM_HEARD_LEN + 4) {
                        ret = 0;
                    } else if (Outstr.substring(HSM_HEARD_LEN, HSM_HEARD_LEN + 4).equals("ND00")) {
                        ret = 1;
                    }
                }
            } catch (Exception e) {
                ret = 0;
            }
            socketUtil.allClose();
            if (ret == 1) {
                if (HSM_flag == 1) {
                    return 0;
                } else {
                    HSM_flag = 2;
                    C_HSM_IP = HSM_2_IP;
                    C_HSM_PORT = HSM_2_PORT;
                    return 2;
                }
            } else if (HSM_flag == 1) {
                return 1;
            }
        }
        return -4;
    }

    /**
     * 生成Mac
     *
     * @param MACKEY
     * @param IV
     * @param datalen
     * @param Indata
     * @return
     * @throws Exception
     */
    private String HSM_CMD_GenerateMAC(String MACKEY, String IV, int datalen, String Indata) {
        String msg = null;
        String buf;
        String outstr;
        try {
            buf = Heard.substring(0, HSM_HEARD_LEN);
            if (HSM_TYPE == 1) {
                String buf1;
                buf1 = "B0830000000000000000";
                buf1 += "00";
                buf1 += MACKEY.substring(0, 4);
                buf1 += "01";
                buf1 += IV.substring(0, 16);
                buf1 += "0000000000000000";
                if("true".equals(isDebugMode)){
                    buf1+="0018";
                }else {
                    buf1 += "001D";
                }
                buf1 += Indata.substring(0, datalen);

                byte[] DataHEX = new byte[buf1.length()];
                byte[] DataByte = new byte[buf1.length() / 2];
                DataHEX = buf1.getBytes();
                socketUtil.Hex2Byte(DataHEX, DataByte, buf1.length());
                buf += new String(DataByte, "ISO-8859-1");

                logger.info(" IN HSM_CMD_GenerateMAC CMD:" + buf1);
                logger.info("buf length===============" + buf.length());
                outstr = socketUtil.HSMCmd(buf.length(), buf);
                if (outstr.substring(HSM_HEARD_LEN, HSM_HEARD_LEN + 1).equals("A")) {
                    int len = outstr.length() - HSM_HEARD_LEN - 9;
                    byte[] outHEX = new byte[len * 2];
                    byte[] outBYTE = new byte[len];
                    String datastr = outstr.substring(HSM_HEARD_LEN + 9, outstr.length());

                    outBYTE = datastr.getBytes("ISO-8859-1");
                    socketUtil.Byte2Hex(outBYTE, outHEX, len);
                    outstr = new String(outHEX, "ISO-8859-1");
                    System.out.println("outstr==========================" + outstr);
                    return outstr;
                } else {
                    logger.error("HSM return data ERROR::" + outstr);
                }
            } else {
                logger.error("ERROR HSM_TYPE:" + HSM_TYPE);
            }
        } catch (Exception e) {
            socketUtil.allClose();
            System.out.println("error IN HSM_CMD_GenerateMAC Exception e:" + e.getMessage());
            logger.error("ERROR In  HSM_CMD_GenerateMAC:" + e.getMessage());
        }
        return msg;
    }

    /**
     * MAC验证
     *
     * @param datalen
     * @param Indata
     * @param orderLast8
     * @param MAC
     * @return
     * @throws Exception
     */
    public int HSM_VerifyMAC(int datalen, String Indata, String orderLast8, String MAC) {
        String outMAC = null;
        int len = Indata.length();

        if ((datalen != len) || (datalen > MAX_DATA_SIZE) || (datalen % 2 == 1)) {
            return -2;
        }
        if (MAC.length() < 8 || MAC.length() > 16) {
            return -3;
        }

        outMAC = HSM_GenerateMAC(datalen, Indata, orderLast8);
        if (outMAC == null) {
            return -1;
        }

        if (outMAC.substring(0, MAC.length()).equals(MAC.substring(0, MAC.length()))) {
            return 0;
        } else {
            return -4;
        }
    }

    /**
     * 计算MAC
     *
     * @param datalen    输入MAC计算数据长度
     * @param Indata     输入MAC计算数据
     * @param orderLast8 卡后8位
     * @return
     */
    public String HSM_GenerateMAC(int datalen, String Indata, String orderLast8) {
        boolean tag = true;
        logger.info("datalenth====" + datalen);
        logger.info("Indata====" + Indata);
        logger.info("orderLast8====" + orderLast8);
        String MAC = null, Instr = null, PAD = "00000000000000000000000000", IV = EncoderHandler.toHexString(orderLast8);
        String[] newData = Indata.split(",");
        String newInData = "";
        //订单号
        String oid = EncoderHandler.toHexString(newData[0]);
        if (oid.length() < 26) {
            newInData += PAD.substring(0, 26 - oid.length()) + oid;
        } else {
            newInData += oid;
        }
        //交易金额 0-999999999
        String amout = EncoderHandler.tenToSixteen(Integer.valueOf(newData[1]));
        if (amout.length() < 8) {
            newInData += PAD.substring(0, 8 - amout.length()) + amout;
        } else {
            newInData += amout;
        }
        //交易类型
        newInData += EncoderHandler.toHexString(newData[2]);

        //收单机构
        String ogcode = EncoderHandler.toHexString(newData[3]);
        int maxorglen = 20;
        if("true".equals(isDebugMode)){
            maxorglen = 10;
        }
        if (ogcode.length() < maxorglen) {
            newInData += PAD.substring(0, maxorglen - ogcode.length()) + ogcode;
        } else {
            newInData += ogcode;
        }
        logger.info("newInData====================" + newInData);
        int len = newInData.length(), i = 0;
        logger.info(String.valueOf(len));
        if (datalen > MAX_DATA_SIZE) {
            tag = false;
            logger.error("In HSM_GenerateMAC input dadalen too longer  Error！！！datalen=" + datalen);
        }
        if (tag) {
            Instr = newInData;
            if (!connect_HSM()) {
                logger.error("In HSM_GenerateMAC connect_HSM  Error！！！");
                return null;
            }
            for (i = 0; len > BLOCK_SIZE * i; i++) {
                if (len > BLOCK_SIZE * (i + 1))
                    MAC = HSM_CMD_GenerateMAC(MAC_KEY, IV, BLOCK_SIZE, Instr.substring(BLOCK_SIZE * i, BLOCK_SIZE * (i + 1)));
                else
                    MAC = HSM_CMD_GenerateMAC(MAC_KEY, IV, len - BLOCK_SIZE * i, Instr.substring(BLOCK_SIZE * i, len));
                IV = MAC;
            }
            if (Long_conect != 1) {
                socketUtil.allClose();
            }
        }
        return MAC;
    }

    /**
     * 检测加密机是否连接状态
     *
     * @return
     */
    private boolean connect_HSM() {
        if (!socketUtil.connectHSM(C_HSM_IP, C_HSM_PORT)) {
            if (HSM_flag == 1) {
                HSM_flag = 2;
                C_HSM_IP = HSM_2_IP;
                C_HSM_PORT = HSM_2_PORT;
            } else {
                HSM_flag = 1;
                C_HSM_IP = HSM_1_IP;
                C_HSM_PORT = HSM_1_PORT;
            }
            if (!socketUtil.connectHSM(C_HSM_IP, C_HSM_PORT)) {
                return false;
            }
        }
        return true;
    }
}
